#include "CoordinateAxisItem.h"
#include <QPainter>
#include <QPainterPath>
#include <QFont>
#include <QDebug>
#include <cmath>       // 添加cmath头文件，用于pow、floor、log10函数
#include <QRegularExpression> // 添加QRegularExpression头文件
#include <QGraphicsPixmapItem>

CoordinateAxisItem::CoordinateAxisItem(QGraphicsItem *parent) :
    QGraphicsPathItem(parent),
    // 绘制的实际长度（世界坐标范围）
    m_xMaxPixe(100),
    m_yMaxPixe(100),
    m_axisColor(Qt::blue),
    m_xTickValueInterval(100),
    m_yTickValueInterval(100),
    // 长刻度线间隔应该绘制的实际像素
    m_xTickPixelInterval(100),
    m_yTickPixelInterval(100),
    // 坐标轴刻度的表达意义（单位类型）
    m_xAxisUnit(Pixel),
    m_yAxisUnit(Pixel),
    // 像素换算比例（从像素到目标单位的转换因子）
    m_xConversionRatio(1.0),
    m_yConversionRatio(1.0),
    // 坐标轴刻度的单位字符串（通过外部接口传入，默认使用像素单位）
    m_xAxisUnitString("px"),
    m_yAxisUnitString("px"),
    // 视图偏移位置（滚动条位置）
    m_offset(QPoint())
{
    // 基本设置
    setFlag(QGraphicsItem::ItemIsSelectable, false);
    setFlag(QGraphicsItem::ItemIsMovable, false);
    setFlag(QGraphicsItem::ItemIgnoresTransformations, true); // 忽略变换，确保即使不接收鼠标事件也不影响下层项
    
    // 禁用事件接收
    setAcceptHoverEvents(false);
    setAcceptDrops(false);
    // 不接收任何鼠标按钮事件
    setAcceptedMouseButtons(Qt::NoButton);

    updatePath(); // 初始化坐标轴路径
}
void CoordinateAxisItem::setAxisRange(double scale, const QSize& imageSize, const QSize& viewportSize, const QPoint& offset)
{
    m_ImageScale=scale;
    m_ImageSize=imageSize;
    m_ViewportSize=viewportSize;
    m_offset=offset;
    redrawCoordinates();
}

void CoordinateAxisItem::redrawCoordinates()
{
    // 设置实际绘制长度（世界坐标范围）
    m_xMaxPixe = qMax(m_ViewportSize.width(),(int)(m_ImageSize.width()*m_ImageScale));
    m_yMaxPixe = qMax(m_ViewportSize.height(),(int)(m_ImageSize.height()*m_ImageScale));
    
    // 计算X轴的合理间隔值和像素
    m_xTickValueInterval = calculateOptimalTickInterval(m_ViewportSize.width(), m_ImageScale,m_xConversionRatio);
    m_xTickPixelInterval = m_xTickValueInterval/m_xConversionRatio*m_ImageScale;

    // 计算Y轴刻度合理间隔值和像素
    m_yTickValueInterval = calculateOptimalTickInterval(m_ViewportSize.height(),m_ImageScale, m_yConversionRatio);
    m_yTickPixelInterval = m_yTickValueInterval/m_yConversionRatio*m_ImageScale;
    updatePath(); // 更新坐标轴路径
}

void CoordinateAxisItem::setAxisColor(const QColor &color)
{
    m_axisColor = color;
    update(); // 触发重绘
}


// 计算优化的刻度间隔，使刻度值呈现为5、10的倍数等整数
// 返回刻度间隔的代表值（不是绘制的像素）
qreal CoordinateAxisItem::calculateOptimalTickInterval(qreal range, qreal scale, qreal conversionRatio) const
{
    // 参数解释：
    // range: 轴的可视的像素范围
    // scale: 当前图像的缩放比例
    // conversionRatio: 当前坐标轴单位换算成未缩放前的原始比例
    
    // 目标：确保刻度间隔范围的值转换成像素再*缩放后的值在50-150像素之间
    
    // 1. 首先确定一个理想的像素间隔范围（50-150像素）
    const double minPixelInterval = 50.0;
    const double maxPixelInterval = 150.0;
    
    // 2. 计算基于当前缩放比例的理想像素间隔
    // 当缩放比例增大时，理想像素间隔应适当减小
    double idealPixelInterval = minPixelInterval + 
                              (maxPixelInterval - minPixelInterval) * 
                              (1.0 - std::min(1.0, scale / 10.0)); // 缩放比例超过10倍时，使用最小像素间隔
    
    // 3. 将理想像素间隔转换为目标单位的间隔值
    // 目标单位间隔 = (理想像素间隔 / 缩放比例) / conversionRatio
    double targetUnitInterval = (idealPixelInterval / scale) * conversionRatio;
    
    // 4. 对目标单位间隔进行优化，使其成为1、2、5、10等简单数字的倍数
    if (targetUnitInterval > 0) {
        // 计算最接近的10的幂次
        double magnitude = pow(10.0, floor(log10(targetUnitInterval)));
        
        // 计算在这个数量级下的最优因子
        double normalized = targetUnitInterval / magnitude;
        
        double factor;
        if (normalized < 1.5) {
            factor = 1.0;
        } else if (normalized < 3.0) {
            factor = 2.0;
        } else if (normalized < 7.5) {
            factor = 5.0;
        } else {
            factor = 10.0;
        }
        
        // 返回优化后的刻度间隔代表值
        return factor * magnitude;
    }
    
    // 如果计算出现问题，返回默认值
    return 10.0;
}

void CoordinateAxisItem::setXAxisProperties(AxisUnit unit, const QString& unitString, double ratio)
{
    m_xAxisUnit = unit;
    m_xAxisUnitString = unitString;
    m_xConversionRatio = ratio > 0 ? ratio : 1.0; // 确保比例为正数
    redrawCoordinates(); // 触发重绘
}

void CoordinateAxisItem::setYAxisProperties(AxisUnit unit, const QString& unitString, double ratio)
{
    m_yAxisUnit = unit;
    m_yAxisUnitString = unitString;
    m_yConversionRatio = ratio > 0 ? ratio : 1.0; // 确保比例为正数
    redrawCoordinates(); // 触发重绘
}

void CoordinateAxisItem::setXAxisUnit(AxisUnit unit)
{
    m_xAxisUnit = unit;
    redrawCoordinates(); // 触发重绘
}

CoordinateAxisItem::AxisUnit CoordinateAxisItem::xAxisUnit() const
{
    return m_xAxisUnit;
}

void CoordinateAxisItem::setYAxisUnit(AxisUnit unit)
{
    m_yAxisUnit = unit;
    update(); // 触发重绘
}

CoordinateAxisItem::AxisUnit CoordinateAxisItem::yAxisUnit() const
{
    return m_yAxisUnit;
}

void CoordinateAxisItem::setXAxisConversionRatio(double ratio)
{
    m_xConversionRatio = ratio;
    redrawCoordinates(); // 触发重绘
}

void CoordinateAxisItem::setXAxisUnitString(const QString& unitString)
{
    m_xAxisUnitString = unitString;
    update(); // 触发重绘
}

QString CoordinateAxisItem::xAxisUnitString() const
{
    return m_xAxisUnitString;
}

void CoordinateAxisItem::setYAxisUnitString(const QString& unitString)
{
    m_yAxisUnitString = unitString;
    update(); // 触发重绘
}

QString CoordinateAxisItem::yAxisUnitString() const
{
    return m_yAxisUnitString;
}

double CoordinateAxisItem::xAxisConversionRatio() const
{
    return m_xConversionRatio;
}

void CoordinateAxisItem::setYAxisConversionRatio(double ratio)
{
    m_yConversionRatio = ratio;
    redrawCoordinates(); // 触发重绘
}

double CoordinateAxisItem::yAxisConversionRatio() const
{
    return m_yConversionRatio;
}

// 格式化坐标值（将世界坐标转换为代表值）
QString CoordinateAxisItem::formatCoordinate(qreal value, const QString& unitString) const
{
    // 根据转换比例将像素值转换为目标单位值
    double convertedValue = value;
    
    // 确定小数位数
    int decimalPlaces = 0;
    if (convertedValue < 1.0) {
        decimalPlaces = 2;
    } else if (convertedValue < 10.0) {
        decimalPlaces = 1;
    }
    
    // 格式化数值
    QString formattedValue;
    if (decimalPlaces > 0) {
        formattedValue = QString::number(convertedValue, 'f', decimalPlaces);
        // 移除末尾的0
        formattedValue.remove(QRegularExpression("\.?0+$"));
    } else {
        formattedValue = QString::number(qRound(convertedValue));
    }
    
    // 添加单位字符串（通过外部接口传入）
    if (!unitString.isEmpty()) {
        formattedValue += " " + unitString;
    }
    
    return formattedValue;
}

void CoordinateAxisItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

bool CoordinateAxisItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
    Q_UNUSED(watched)
    Q_UNUSED(event)
    // 始终返回false，让事件继续传递
    return false;
}

void CoordinateAxisItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

void CoordinateAxisItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    // 显式忽略事件，让事件能够穿透到下层item
    event->ignore();
}

// 更新坐标轴路径和刻度位置
void CoordinateAxisItem::updatePath()
{
    QPainterPath path;

    // 计算考虑偏移后的实际位置
    qreal actualOffsetX = m_FixedOffsetX + m_offset.x();
    qreal actualOffsetY = m_FixedOffsetY + m_offset.y();
    
    // X轴从左到右在底部，跟随偏移
    path.moveTo(actualOffsetX, actualOffsetY);
    path.lineTo(m_xMaxPixe + m_FixedOffsetX, actualOffsetY);
    
    // Y轴从上到下在左侧，跟随偏移
    path.moveTo(actualOffsetX, actualOffsetY);
    path.lineTo(actualOffsetX, m_yMaxPixe + m_FixedOffsetX);
    
    setPath(path);
    
    setZValue(1000);

    update(); // 触发重绘
}

QRectF CoordinateAxisItem::boundingRect() const
{

    // 仅包含实际坐标轴和刻度文本的区域，而不是整个图像区域
    // 左侧Y轴区域 + 底部X轴区域
    QRectF rect(0, m_FixedOffsetY - 50, 100, m_yMaxPixe + 50); // Y轴和其刻度文本
    
    // 添加X轴区域
    rect = rect.united(QRectF(m_FixedOffsetX, 0, m_xMaxPixe + 50, 50)); // X轴和其刻度文本
    
    return rect;
}

void CoordinateAxisItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->save();
    // 启用抗锯齿优化
    painter->setRenderHint(QPainter::Antialiasing);
    

    
    // 计算考虑偏移后的实际位置
    qreal xAxisYPos = m_FixedOffsetY + m_offset.y();
    qreal yAxisXPos = m_FixedOffsetX + m_offset.x();
    
    
    // 绘制X轴背景，跟随Y偏移
    painter->setBrush(QColor(255, 255, 255, 255));  // 半透明白色背景
    painter->setPen(Qt::NoPen);
    painter->drawRect(QRectF(m_FixedOffsetX, xAxisYPos - m_FixedOffsetY, m_xMaxPixe, m_FixedOffsetY));
    
    // 绘制Y轴背景，跟随X偏移
    painter->drawRect(QRectF(yAxisXPos - m_FixedOffsetX, m_FixedOffsetY, m_FixedOffsetX, m_yMaxPixe));
    
    // 设置坐标轴颜色
    QPen pen(m_axisColor);
    pen.setWidth(1);
    painter->setPen(pen);
    
    // 绘制坐标轴路径
    painter->drawPath(path());
    
    // 长刻度线长度
    const qreal longTickLength = 10;
    // 短刻度线长度
    const qreal shortTickLength = 4;
    // 短刻度线间隔（长刻度线间隔的1/5）
    const double xShortTickInterval = m_xTickPixelInterval / 5.0;
    const double yShortTickInterval = m_yTickPixelInterval / 5.0;
    
    // 计算总刻度数
    int totalXTicks = static_cast<int>(m_xMaxPixe / xShortTickInterval) + 1;
    int totalYTicks = static_cast<int>(m_yMaxPixe / yShortTickInterval) + 1;
    
    // 绘制X轴刻度线和文本
    for (int i = 0; i < totalXTicks; ++i) {
        double xTickPixe = i * xShortTickInterval;
        bool isLongTick = (i % 5 == 0);
        qreal xPos = xTickPixe + m_FixedOffsetX;
        
        // 绘制刻度线（向上绘制）
        if (isLongTick)
        {
            painter->drawLine(QPointF(xPos, xAxisYPos), QPointF(xPos, xAxisYPos - longTickLength));
            // 计算实际刻度值
            double actualValue = m_xTickValueInterval * i / 5.0;
            QString text = formatCoordinate(actualValue, m_xAxisUnitString);
            QFontMetrics metrics(painter->font());
            painter->drawText(QPointF(xPos, xAxisYPos - shortTickLength - metrics.height()), text);
        }
        else
        {
            painter->drawLine(QPointF(xPos, xAxisYPos), QPointF(xPos, xAxisYPos - shortTickLength));
        }
    }
    
    // 绘制Y轴刻度线和文本
    for (int i = 0; i < totalYTicks; ++i) {
        double yTickPixe = i * yShortTickInterval;
        bool isLongTick = (i % 5 == 0);
        qreal yPos = yTickPixe + m_FixedOffsetY;
        
        // 绘制刻度线（向左绘制）
        if (isLongTick)
        {
            painter->drawLine(QPointF(yAxisXPos, yPos), QPointF(yAxisXPos - longTickLength, yPos));
            // 计算实际刻度值
            double actualValue = m_yTickValueInterval * i / 5.0;
            QString text = formatCoordinate(actualValue, m_yAxisUnitString);
            painter->save();
            // 文本位置严格基于刻度线位置计算，确保在长刻度线左侧且垂直居中
            QFontMetrics metrics(painter->font());
            painter->translate(yAxisXPos - shortTickLength - metrics.height(), yPos + metrics.horizontalAdvance(text));
            painter->rotate(-90);
            painter->drawText(QPointF(0, 0), text);
            painter->restore();
        }
        else
        {
            painter->drawLine(QPointF(yAxisXPos, yPos), QPointF(yAxisXPos - shortTickLength, yPos));
        }
    }
    
    // 在坐标轴交界处绘制一个白色矩形，遮挡部分线条以避免交点不美观
    // 随着偏移而偏移
    painter->setBrush(Qt::white);
    painter->setPen(Qt::white);
    painter->drawRect(QRectF(yAxisXPos - m_FixedOffsetX, xAxisYPos - m_FixedOffsetY, m_FixedOffsetX, m_FixedOffsetY));
    
    painter->restore();
}

/**
 * @brief 获取固定偏移
 * @return 返回x轴和y轴的偏移
 */
QSize CoordinateAxisItem::getFixedOffset() const
{
    return QSize(m_FixedOffsetX,m_FixedOffsetY);
}
